﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_TYPE_INFO_H
#define _UXS_TYPE_INFO_H

#pragma once

#include "../Types/TypeId.h"
#include "../BaseTypes/TFloat.h"
#include "../BaseTypes/TFixed.h"
#include "../BaseTypes/THalf.h"
#include "../BaseTypes/TUFloat.h"
#include "TypeTraits.h"
#include "TemplateUtils.h"
#include "TemplateMath.h"


namespace UX_STL
{
namespace UXTypes
{

	namespace _ctime_hidden_
	{
		// Limits
#	pragma warning (push)
#	pragma warning (disable: 4723)

#	ifdef UX_MATH_REAL_LIMITS

		const	uint8	UINT8_MAX			= uint8 ( -1 );
		const	uint16	UINT16_MAX			= uint16( -1 );
		const	uint32	UINT32_MAX			= uint32( -1 );
		const	uint64	UINT64_MAX			= uint64( -1 );

		const	int8	INT8_MIN			= int8 ( 1 << (CompileTime::SizeOf<int8>::bits-1) );
		const	int16	INT16_MIN			= int16( 1 << (CompileTime::SizeOf<int16>::bits-1) );
		const	int32	INT32_MIN			= int32(1) << (CompileTime::SizeOf<int32>::bits-1);
		const	int64	INT64_MIN			= int64(1) << (CompileTime::SizeOf<int64>::bits-1);

		const	int8	INT8_MAX			= UINT8_MAX  & ~INT8_MIN;
		const	int16	INT16_MAX			= UINT16_MAX & ~INT16_MIN;
		const	int32	INT32_MAX			= UINT32_MAX & ~INT32_MIN;
		const	int64	INT64_MAX			= UINT64_MAX & ~INT64_MIN;
		/*
		const	float	FLOAT_MAX			= FLT_MAX;
		const	float	FLOAT_MIN			= FLT_MIN;

		const	double	DOUBLE_MAX			= DBL_MAX;
		const	double	DOUBLE_MIN			= DBL_MIN;
	
		const	uint	FLOAT_MAX_POW		= FLT_MAX_10_EXP;
		const	uint	DOUBLE_MAX_POW		= DBL_MAX_10_EXP;
		*
		const	float	FLOAT_MAX			= 3.4e+38f;
		const	float	FLOAT_MIN			= 1.2e-38f;

		const	double	DOUBLE_MAX			= 1.7e+308;
		const	double	DOUBLE_MIN			= 2.3e-308;
		*/
		const	float	FLOAT_MAX			= static_cast< float const &>( 0x7F7FFFFF );
		const	float	FLOAT_MIN			= static_cast< float const &>( 0x00800000 );

		const	double	DOUBLE_MAX			= static_cast< double const &>( 0x7FEFFFFFFFFFFFFFull );
		const	double	DOUBLE_MIN			= static_cast< double const &>( 0x0010000000000000ull );

		const	uint	FLOAT_MAX_POW		= 38;
		const	uint	DOUBLE_MAX_POW		= 308;

		const	float	FLOAT_INF			= 1.0f / static_cast< float const  &>( uint32(0) );
		const	double	DOUBLE_INF			= 1.0  / static_cast< double const &>( uint64(0) );

		const	float	FLOAT_NAN			= static_cast< float const  &>( uint32(0) ) / static_cast< float const  &>( uint32(0) );
		const	double	DOUBLE_NAN			= static_cast< double const &>( uint64(0) ) / static_cast< double const &>( uint64(0) );

#	else

		const	uint8	UINT8_MAX			= 0xFF;
		const	uint16	UINT16_MAX			= 0xFFFF;
		const	uint32	UINT32_MAX			= 0xFFFFFFFF;
		const	uint64	UINT64_MAX			= 0xFFFFFFFFFFFFFFFFull;

		const	int8	INT8_MIN			= int8 (0x80);
		const	int16	INT16_MIN			= int16(0x8000);
		const	int32	INT32_MIN			= 0x80000000;
		const	int64	INT64_MIN			= 0x8000000000000000ull;

		const	int8	INT8_MAX			= UINT8_MAX  & ~INT8_MIN;
		const	int16	INT16_MAX			= UINT16_MAX & ~INT16_MIN;
		const	int32	INT32_MAX			= UINT32_MAX & ~INT32_MIN;
		const	int64	INT64_MAX			= UINT64_MAX & ~INT64_MIN;

		const	float	FLOAT_MAX			= static_cast< float const &>( 0x7F7FFFFF );
		const	float	FLOAT_MIN			= static_cast< float const &>( 0x00800000 );

		const	double	DOUBLE_MAX			= static_cast< double const &>( 0x7FEFFFFFFFFFFFFFull );
		const	double	DOUBLE_MIN			= static_cast< double const &>( 0x0010000000000000ull );
	
		const	uint	FLOAT_MAX_POW		= 38;
		const	uint	DOUBLE_MAX_POW		= 308;
		
		const	float	FLOAT_INF			= static_cast< float const  &>( 0x7F800000 );
		const	double	DOUBLE_INF			= static_cast< double const &>( 0x7FF0000000000000ull );

		const	float	FLOAT_NAN			= static_cast< float const  &>( 0xFFC00000 );
		const	double	DOUBLE_NAN			= static_cast< double const &>( 0xFFF8000000000000ull );

#	endif	// UX_MATH_REAL_LIMITS

		const	float	FLOAT_EPSILON		= 1.0e-6f;
		const	double	DOUBLE_EPSILON		= 1.0e-8;
		
#	pragma warning (pop)

		enum ETypeDescriptor
		{
			UNKNOWN		= 0,
			VOID		= 1 << 1,
			FLOAT		= 1 << 2,
			INTEGER		= 1 << 3,
			FIXED		= 1 << 4,
			BOOL		= 1 << 5,

			SIGNED		= 1 << 6,
			UNSIGNED	= 1 << 7,

			_MASK		= (1 << 8) - 1,

			COMPOUND	= 1 << 8,	// has inner type
			VECTOR		= 1 << 9,	// vector type
			MATRIX		= 1 << 10,	// matrix type
		};
	}


	
	template <typename T>	struct TypeInfo;


	//
	// Type Descriptor
	//

	namespace TypeDescriptor
	{

		// Get Inner Type
		template <typename T>
		struct InnerType
		{
			template <typename U, bool I>
			struct _GetInner;

			template <typename U>
			struct _GetInner<U,false>
			{
				typedef typename TypeInfo< U >::inner_type	type;
			};

			template <typename U>
			struct _GetInner<U,true>
			{
				typedef typename _GetInner< typename TypeInfo< U >::inner_type,
											(TypeInfo< U >::FLAGS & _ctime_hidden_::COMPOUND) != 0 >::type	type;
			};

			typedef typename _GetInner< T, true >::type		type;
		};



		// get type info (for const types)
		template <typename T>
		struct GetTypeInfo {
			typedef TypeInfo< typename TypeTraits::RemoveConstVolatile<T>::type >	type;
		};


		// Is<Type>
		template <typename T>
		struct IsFloat {
			static const bool	value = ( int(TypeInfo< T >::FLAGS) & int(_ctime_hidden_::FLOAT) ) != 0;
		};

		template <typename T>
		struct IsInteger {
			static const bool	value = ( int(TypeInfo< T >::FLAGS) & int(_ctime_hidden_::INTEGER) ) != 0;
		};

		template <typename T>
		struct IsFixed {
			static const bool	value = ( int(TypeInfo< T >::FLAGS) & int(_ctime_hidden_::FIXED) ) != 0;
		};

		template <typename T>
		struct IsSigned {
			static const bool	value = ( int(TypeInfo< T >::FLAGS) & int(_ctime_hidden_::SIGNED) ) != 0;
		};

		template <typename T>
		struct IsUnsigned {
			static const bool	value = ( int(TypeInfo< T >::FLAGS) & int(_ctime_hidden_::UNSIGNED) ) != 0;
		};

		template <typename T1, typename T2>
		struct CmpTypes {
			static const bool	value = ( TypeInfo< T1 >::UID == TypeInfo< T2 >::UID );
		};

		template <typename T1, typename T2>
		struct IsSameTypes {
			static const bool	value = false;
		};

		template <typename T>
		struct IsSameTypes <T,T> {
			static const bool	value = true;
		};


		template <typename T>
		struct IsVoid {
			static const bool	value = false;
		};

		template <>
		struct IsVoid<void> {
			static const bool	value = true;
		};


		// TODO: IsPOD
		template <typename T>
		struct IsPOD {
			static const bool	value = false;
		};


		// Must Be <Type>
		template <typename T>
		struct MustBeInteger {
			T	__int_value : 1;
		};

		template <typename T>
		struct MustBeFloat {
			STATIC_ASSERTE( IsFloat<T>::value );
		};


		// MainType
		template <typename T1, typename T2>
		struct _MainTypeCheck {
			static const bool	_f1		= TypeDescriptor::IsFloat<T1>::value;
			static const bool	_f2		= TypeDescriptor::IsFloat<T2>::value;
			static const bool	value	= (_f1 != _f2) ? _f1 : (sizeof(T1) >= sizeof(T2));
		};


		template <typename T1, typename T2>
		struct MainType {
			typedef typename SwitchType< _MainTypeCheck< T1, T2 >::value, T1, T2 >::type			type;
		};

		template <typename T1, typename T2, typename T3>
		struct MainType3 {
			typedef typename SwitchType< _MainTypeCheck< T1, T2 >::value, T1, T2 >::type			_t12;
			typedef typename SwitchType< _MainTypeCheck< _t12, T3 >::value, _t12, T3 >::type		type;
		};

		template <typename T1, typename T2, typename T3, typename T4>
		struct MainType4 {
			typedef typename SwitchType< _MainTypeCheck< T1, T2 >::value, T1, T2 >::type			_t12;
			typedef typename SwitchType< _MainTypeCheck< T3, T4 >::value, T3, T4 >::type			_t34;
			typedef typename SwitchType< _MainTypeCheck< _t12, _t34 >::value, _t12, _t34 >::type	type;
		};

		template <	typename T01 = void, typename T02 = void, typename T03 = void, typename T04 = void,
					typename T05 = void, typename T06 = void, typename T07 = void, typename T08 = void,
					typename T09 = void, typename T10 = void, typename T11 = void, typename T12 = void,
					typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void >
		struct MainTypeL {
			typedef typename MainType4< T01, T02, T03, T04 >::type	_t1;
			typedef typename MainType4< T05, T06, T07, T08 >::type	_t2;
			typedef typename MainType4< T09, T10, T11, T12 >::type	_t3;
			typedef typename MainType4< T13, T14, T15, T16 >::type	_t4;
			typedef typename MainType4< _t1, _t2, _t3, _t4 >::type	type;
		};


		template <typename ToType, typename FromType>
		static inline bool CanCastTo (FromType *p)
		{
			if ( p == null )
				return true;

			DESCTOP_ONLY( return dynamic_cast< ToType *>( p ) != null );
			MOBILE_ONLY( return true );
		}

	}	// TypeDescriptor



	//
	// Min/Max Value
	//

	template <typename T>
	inline T MinValue(const T&)
	{
		return TypeInfo< T >::Min();
	}

	template <typename T>
	inline T MaxValue(const T&)
	{
		return TypeInfo< T >::Max();
	}



	//
	// Infinity, NaN
	//
	
	template <typename T>
	inline T  Infinity()
	{
		return TypeInfo< T >::Inf();
	}

	template <typename T>
	inline T  NaN()
	{
		return TypeInfo< T >::NaN();
	}
	
	template <typename T>
	inline bool IsNaN (const T& x)
	{
		return x != x;
	}

	template <typename T>
	inline bool IsInfinity (const T& x)
	{
		return not IsFinite( x );
	}

	template <typename T>
	inline bool IsFinite (const T& x)
	{
		return ( x != Infinity<T>() and x != -Infinity<T>() );
	}



	//
	// Check Value
	//
	/*
	template <typename T>
	inline bool CheckValue(const T& val)
	{
		return true;
	}


	template <>
	inline bool CheckValue<float>(const float& val)
	{
		return ( UXMath::Abs(val) <= _ctime_hidden_::FLOAT_MAX or
				 UXMath::Abs(val) >= _ctime_hidden_::FLOAT_MIN );
	}


	template <>
	inline bool CheckValue<double>(const double& val)
	{
		return ( UXMath::Abs(val) <= _ctime_hidden_::DOUBLE_MAX or
				 UXMath::Abs(val) >= _ctime_hidden_::DOUBLE_MIN );
	}
	*/


	//
	// Near Integer Type
	//
	
	namespace NearInt
	{
		template <usize Size>	struct _TSizeU    {};
		template <>				struct _TSizeU<1> { typedef uint8  type; };
		template <>				struct _TSizeU<2> { typedef uint16 type; };
		template <>				struct _TSizeU<4> { typedef uint32 type; };
		template <>				struct _TSizeU<8> { typedef uint64 type; };
		
		template <usize Size>	struct _TSizeI    {};
		template <>				struct _TSizeI<1> { typedef int8   type; };
		template <>				struct _TSizeI<2> { typedef int16  type; };
		template <>				struct _TSizeI<4> { typedef int32  type; };
		template <>				struct _TSizeI<8> { typedef int64  type; };

		template <usize Bits>	struct _BitsToSize { enum { value = (Bits <= 8 ? 8 :
																	(Bits <= 16 ? 16 :
																	(Bits <= 32 ? 32 : 64) ) ) >> 3 }; };


		template <typename T>
		struct Unsigned {
			typedef typename _TSizeU< sizeof(T) >::type	type;
		};

		template <typename T>
		struct Signed {
			typedef typename _TSizeI< sizeof(T) >::type	type;
		};

		
		template <usize Bits>
		struct UnsignedBits {
			typedef typename _TSizeU< _BitsToSize< Bits >::value >::type	type;
		};

		template <usize Bits>
		struct SignedBits {
			typedef typename _TSizeI< _BitsToSize< Bits >::value >::type	type;
		};

		
		template <usize Size>
		struct UnsignedSize {
			typedef typename _TSizeU< Size >::type	type;
		};

		template <usize Size>
		struct SignedSize {
			typedef typename _TSizeI< Size >::type	type;
		};


		template <typename T1, typename T2>
		struct MainUnsignedType {
			typedef typename _TSizeU< CompileTime::MinMax< usize, sizeof(T1), sizeof(T2) >::max >::type	type;
		};

		template <typename T1, typename T2, typename T3>
		struct MainUnsignedType3 {
			typedef typename _TSizeU< CompileTime::MinMax3< usize, sizeof(T1), sizeof(T2), sizeof(T3) >::max >::type	type;
		};

		template <typename T1, typename T2>
		struct MainSignedType {
			typedef typename _TSizeI< CompileTime::MinMax< usize, sizeof(T1), sizeof(T2) >::max >::type	type;
		};

		template <typename T1, typename T2, typename T3>
		struct MainSignedType3 {
			typedef typename _TSizeI< CompileTime::MinMax3< usize, sizeof(T1), sizeof(T2), sizeof(T3) >::max >::type	type;
		};



		template <usize Value>
		struct UnsignedValue {
			typedef typename SwitchType< (Value <= _ctime_hidden_::UINT8_MAX), uint8,
						typename SwitchType< (Value <= _ctime_hidden_::UINT16_MAX), uint16,
							typename SwitchType< (Value <= _ctime_hidden_::UINT32_MAX), uint32, uint64 >::type
						>::type
					>::type			type;
		};

		template <isize Value>
		struct SignedValue {
			typedef typename SwitchType< (Value >= _ctime_hidden_::INT8_MIN and Value <= _ctime_hidden_::INT8_MAX), int8,
						typename SwitchType< (Value >= _ctime_hidden_::INT16_MIN and Value <= _ctime_hidden_::INT16_MAX), int16,
							typename SwitchType< (Value >= _ctime_hidden_::INT32_MIN and Value <= _ctime_hidden_::INT32_MAX), int32, int64 >::type
						>::type
					>::type			type;
		};
	};


	//
	// Larger Integer Type
	//
	
	namespace LargerInt
	{
		template <typename T>
		struct Unsigned {
			enum _t {
				value	= CompileTime::MinMax< int, (sizeof(T)<<1), 1 >::max,
			};
			typedef typename NearInt::_TSizeU< sizeof(T) >::type	type;
		};

		template <typename T>
		struct Signed {
			enum _t {
				value	= CompileTime::MinMax< int, (sizeof(T)<<1), 1 >::max,
			};
			typedef typename NearInt::_TSizeI< value >::type	type;
		};
	};


	//
	// Lesser Integer Type
	//
	
	namespace LesserInt
	{
		template <typename T>
		struct Unsigned {
			enum _t {
				value	= CompileTime::MinMax< int, (sizeof(T)>>1), 1 >::max,
			};
			typedef typename NearInt::_TSizeU< sizeof(T) >::type	type;
		};

		template <typename T>
		struct Signed {
			enum _t {
				value	= CompileTime::MinMax< int, (sizeof(T)>>1), 1 >::max,
			};
			typedef typename NearInt::_TSizeI< value >::type	type;
		};
	};



	//
	// Near Float Type
	//

	namespace NearFloat
	{
		template <usize SizeValue>
		struct FromSize {
			typedef typename SwitchType< (SizeValue <= sizeof(float)), float,
						typename SwitchType< (SizeValue <= sizeof(double)), double,
							long double >::type >::type									type;
						
		};

		template <typename T>
		struct FromType {
			typedef typename FromSize< sizeof(T) >::type	type;
		};
	};




#	define _CHECK_SIMILAR_TYPES() \
		STATIC_ASSERT(	sizeof(type) == sizeof(Similar_Unsigned) and \
						sizeof(type) == sizeof(Similar_Signed) and \
						sizeof(type) == sizeof(Similar_Float) and \
						sizeof(type) == sizeof(Similar_UInt) and \
						sizeof(type) == sizeof(Similar_Int), "types size mismatch" );

#	define _TYPE_INFO_WITH_INNER_TYPE( _type, _inner_type, _type_name ) \
		template <> \
		struct TypeInfo<_type> \
		{ \
			typedef _type			type; \
			typedef _inner_type		inner_type; \
			\
			typedef TypeInfo< _inner_type >::Similar_Unsigned	Similar_Unsigned; \
			typedef TypeInfo< _inner_type >::Similar_Signed		Similar_Signed; \
			typedef TypeInfo< _inner_type >::Similar_Float		Similar_Float; \
			typedef TypeInfo< _inner_type >::Similar_UInt		Similar_UInt; \
			typedef TypeInfo< _inner_type >::Similar_Int		Similar_Int; \
			\
			enum { \
				FLAGS	= (int)TypeInfo< _inner_type >::FLAGS | int(_ctime_hidden_::COMPOUND), \
				UID		= __COUNTER__, \
			}; \
			\
			static			 _type  Max()		{ return _type( TypeInfo< _inner_type >::Max() ); } \
			static			 _type  Min()		{ return _type( TypeInfo< _inner_type >::Min() ); } \
			\
			static			 _type	Epsilon()	{ return _type( TypeInfo< _inner_type >::Epsilon() ); } \
			static constexpr uint	SignBit()	{ return TypeInfo< _inner_type >::SignBit(); } \
			\
			static const char *		Name()		{ return _type_name; } \
			\
			_CHECK_SIMILAR_TYPES(); \
		}
	


	//
	// Type Info (example)
	//
	
	template <typename T>
	struct TypeInfo
	{
		/*	
		typedef T		type;
		typedef T		inner_type;

		// similar types //
		typedef void	Similar_Unsigned;
		typedef void	Similar_Signed;
		typedef void	Similar_Float;
		typedef void	Similar_UInt;
		typedef void	Similar_Int;
		*/
		// type descriptor //
		enum {
			FLAGS	= _ctime_hidden_::UNKNOWN,	// type descriptor flags
			UID		= -1,					// unique identifer
		};
		/*
		static constexpr type	Max()		{ return type(1); }
		static constexpr type	Min()		{ return type(0); }
		static constexpr type	Inf()		{ return type(0); }
		static constexpr type	NaN()		{ return type(0); }

		static constexpr type	Epsilon()	{ return type(0); }
		static constexpr uint	SignBit()	{ return 0; }

		static const char *		Name()		{ return ""; }

		STATIC_WARNING( "unknown type" );
		*/
	};


	template <>
	struct TypeInfo<void>
	{
		typedef void		type;
		typedef type		inner_type;

		// similar types //
		typedef void		Similar_Unsigned;
		typedef void		Similar_Signed;
		typedef void		Similar_Float;
		typedef void		Similar_UInt;
		typedef void		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= _ctime_hidden_::VOID,
			UID		= __COUNTER__,
		};

		static void				Max()		{ return void(); }
		static void				Min()		{ return void(); }
		
		static void				Epsilon()	{ return void(); }
		static constexpr uint	SignBit()	{ return 0; }
		
		static const char *		Name()		{ return "void"; }
	};


	template <>
	struct TypeInfo<bool>
	{
		typedef bool		type;
		typedef type		inner_type;

		// similar types //
		typedef uint8		Similar_Unsigned;
		typedef int8		Similar_Signed;
		typedef float8u_t	Similar_Float;
		typedef uint8		Similar_UInt;
		typedef int8		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::BOOL | (int)_ctime_hidden_::UNSIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return true; }
		static constexpr type			Min()		{ return false; }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return 0; }
		
		static const char *				Name()		{ return "bool"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<int8>
	{
		typedef int8		type;
		typedef type		inner_type;

		// similar types //
		typedef uint8		Similar_Unsigned;
		typedef int8		Similar_Signed;
		typedef float8u_t	Similar_Float;
		typedef uint8		Similar_UInt;
		typedef int8		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::INT8_MAX; }
		static constexpr type			Min()		{ return _ctime_hidden_::INT8_MIN; }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "int8"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<uint8>
	{
		typedef uint8		type;
		typedef type		inner_type;

		// similar types //
		typedef uint8		Similar_Unsigned;
		typedef int8		Similar_Signed;
		typedef float8u_t	Similar_Float;
		typedef uint8		Similar_UInt;
		typedef int8		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::UNSIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::UINT8_MAX; }
		static constexpr type			Min()		{ return type(0); }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return 0; }
		
		static const char *				Name()		{ return "uint8"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<char>
	{
		typedef char		type;
		typedef type		inner_type;

		// similar types //
		typedef uint8		Similar_Unsigned;
		typedef int8		Similar_Signed;
		typedef float8u_t	Similar_Float;
		typedef uint8		Similar_UInt;
		typedef int8		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::INT8_MAX; }
		static constexpr type			Min()		{ return _ctime_hidden_::INT8_MIN; }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "char"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<int16>
	{
		typedef int16		type;
		typedef type		inner_type;

		// similar types //
		typedef uint16		Similar_Unsigned;
		typedef int16		Similar_Signed;
		typedef float16_t	Similar_Float;
		typedef uint16		Similar_UInt;
		typedef int16		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::INT16_MAX; }
		static constexpr type			Min()		{ return _ctime_hidden_::INT16_MIN; }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "int16"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<uint16>
	{
		typedef uint16		type;
		typedef type		inner_type;

		// similar types //
		typedef uint16		Similar_Unsigned;
		typedef int16		Similar_Signed;
		typedef float16_t	Similar_Float;
		typedef uint16		Similar_UInt;
		typedef int16		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::UNSIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::UINT16_MAX; }
		static constexpr type			Min()		{ return type(0); }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return 0; }
		
		static const char *				Name()		{ return "uint16"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <> struct TypeInfo<wchar> : TypeInfo<int16> {};


	template <>
	struct TypeInfo<int32>
	{
		typedef int32		type;
		typedef type		inner_type;

		// similar types //
		typedef uint32		Similar_Unsigned;
		typedef int32		Similar_Signed;
		typedef float		Similar_Float;
		typedef uint32		Similar_UInt;
		typedef int32		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::INT32_MAX; }
		static constexpr type			Min()		{ return _ctime_hidden_::INT32_MIN; }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "int32"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<uint32>
	{
		typedef uint32		type;
		typedef type		inner_type;

		// similar types //
		typedef uint32		Similar_Unsigned;
		typedef int32		Similar_Signed;
		typedef float		Similar_Float;
		typedef uint32		Similar_UInt;
		typedef int32		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::UNSIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::UINT32_MAX; }
		static constexpr type			Min()		{ return type(0); }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return 0; }
		
		static const char *				Name()		{ return "uint32"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<int64>
	{
		typedef int64		type;
		typedef type		inner_type;

		// similar types //
		typedef uint64		Similar_Unsigned;
		typedef int64		Similar_Signed;
		typedef double		Similar_Float;
		typedef uint64		Similar_UInt;
		typedef int64		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::INT64_MAX; }
		static constexpr type			Min()		{ return _ctime_hidden_::INT64_MIN; }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "int64"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<uint64>
	{
		typedef uint64		type;
		typedef type		inner_type;

		// similar types //
		typedef uint64		Similar_Unsigned;
		typedef int64		Similar_Signed;
		typedef double		Similar_Float;
		typedef uint64		Similar_UInt;
		typedef int64		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::INTEGER | (int)_ctime_hidden_::UNSIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::UINT64_MAX; }
		static constexpr type			Min()		{ return 0; }
		
		static constexpr type			Epsilon()	{ return type(0); }
		static constexpr uint			SignBit()	{ return 0; }
		
		static const char *				Name()		{ return "uint64"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<float8u_t>
	{
		typedef float8u_t	type;
		typedef type		inner_type;

		// similar types //
		typedef float8u_t	Similar_Unsigned;
		typedef float8u_t	Similar_Signed;
		typedef float8u_t	Similar_Float;
		typedef uint8		Similar_UInt;
		typedef int8		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::FLOAT | (int)_ctime_hidden_::UNSIGNED,
			UID		= __COUNTER__,
		};

		static			 type			Max()		{ return (type) _ctime_hidden_::FLOAT_MAX; }
		static			 type			Min()		{ return (type) _ctime_hidden_::FLOAT_MIN; }
		static			 type			Inf()		{ return type(0); }	// TODO
		static			 type			NaN()		{ return type(0); }	// TODO
		
		static			 type			Epsilon()	{ return (type) _ctime_hidden_::FLOAT_EPSILON; }
		static constexpr uint			SignBit()	{ return 0; }
		
		static const char *				Name()		{ return "float8u"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<float16_t>
	{
		typedef float16_t	type;
		typedef type		inner_type;

		// similar types //
		typedef float16_t	Similar_Unsigned;
		typedef float16_t	Similar_Signed;
		typedef float16_t	Similar_Float;
		typedef uint16		Similar_UInt;
		typedef int16		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::FLOAT | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static			 type			Max()		{ return (type) _ctime_hidden_::FLOAT_MAX; }
		static			 type			Min()		{ return (type) _ctime_hidden_::FLOAT_MIN; }
		static			 type			Inf()		{ return type(0); }	// TODO
		static			 type			NaN()		{ return type(0); }	// TODO
		
		static			 type			Epsilon()	{ return (type) _ctime_hidden_::FLOAT_EPSILON; }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "float16"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<float>
	{
		typedef float		type;
		typedef type		inner_type;

		// similar types //
		typedef float		Similar_Unsigned;
		typedef float		Similar_Signed;
		typedef float		Similar_Float;
		typedef uint32		Similar_UInt;
		typedef int32		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::FLOAT | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::FLOAT_MAX; }
		static constexpr type			Min()		{ return _ctime_hidden_::FLOAT_MIN; }
		static			 type			Inf()		{ return _ctime_hidden_::FLOAT_INF; }
		static			 type			NaN()		{ return _ctime_hidden_::FLOAT_NAN; }
		
		static constexpr type			Epsilon()	{ return _ctime_hidden_::FLOAT_EPSILON; }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "float"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<double>
	{
		typedef double		type;
		typedef type		inner_type;

		// similar types //
		typedef double		Similar_Unsigned;
		typedef double		Similar_Signed;
		typedef double		Similar_Float;
		typedef uint64		Similar_UInt;
		typedef int64		Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::FLOAT | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::DOUBLE_MAX; }
		static constexpr type			Min()		{ return _ctime_hidden_::DOUBLE_MIN; }
		static			 type			Inf()		{ return _ctime_hidden_::DOUBLE_INF; }
		static			 type			NaN()		{ return _ctime_hidden_::DOUBLE_NAN; }
		
		static constexpr type			Epsilon()	{ return _ctime_hidden_::DOUBLE_EPSILON; }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "double"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<long double>
	{
		typedef long double		type;
		typedef type			inner_type;

		// similar types //
		typedef long double		Similar_Unsigned;
		typedef long double		Similar_Signed;
		typedef long double		Similar_Float;
		typedef uint64			Similar_UInt;
		typedef int64			Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::FLOAT | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static constexpr type			Max()		{ return _ctime_hidden_::DOUBLE_MAX; }
		static constexpr type			Min()		{ return _ctime_hidden_::DOUBLE_MIN; }
		static			 type			Inf()		{ return _ctime_hidden_::DOUBLE_INF; }
		static			 type			NaN()		{ return _ctime_hidden_::DOUBLE_NAN; }
		
		static constexpr type			Epsilon()	{ return _ctime_hidden_::DOUBLE_EPSILON; }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "long double"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<fixed16_t>
	{
		typedef fixed16_t		type;
		typedef type			inner_type;

		// similar types //
		typedef float16_t		Similar_Unsigned;
		typedef float16_t		Similar_Signed;
		typedef float16_t		Similar_Float;
		typedef uint16			Similar_UInt;
		typedef int16			Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::FIXED | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static			 type			Max()		{ return type( TypeInfo< type::half_int_t >::Max(), TypeInfo< type::half_uint_t >::Max() ); }
		static			 type			Min()		{ return type( TypeInfo< type::half_int_t >::Min(), TypeInfo< type::half_uint_t >::Max() ); }
		
		static			 type			Epsilon()	{ return type( 0, 1 ); }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "fixed16"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<fixed32_t>
	{
		typedef fixed32_t		type;
		typedef type			inner_type;

		// similar types //
		typedef fixed32_t		Similar_Unsigned;
		typedef fixed32_t		Similar_Signed;
		typedef float			Similar_Float;
		typedef uint32			Similar_UInt;
		typedef int32			Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::FIXED | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static			 type			Max()		{ return type( TypeInfo< type::half_int_t >::Max(), TypeInfo< type::half_uint_t >::Max() ); }
		static			 type			Min()		{ return type( TypeInfo< type::half_int_t >::Min(), TypeInfo< type::half_uint_t >::Max() ); }
		
		static			 type			Epsilon()	{ return type( 0, 1 ); }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "fixed32"; }

		_CHECK_SIMILAR_TYPES();
	};


	template <>
	struct TypeInfo<fixed64_t>
	{
		typedef fixed64_t		type;
		typedef type			inner_type;

		// similar types //
		typedef fixed64_t		Similar_Unsigned;
		typedef fixed64_t		Similar_Signed;
		typedef double			Similar_Float;
		typedef uint64			Similar_UInt;
		typedef int64			Similar_Int;

		// type descriptor //
		enum {
			FLAGS	= (int)_ctime_hidden_::FIXED | (int)_ctime_hidden_::SIGNED,
			UID		= __COUNTER__,
		};

		static			 type			Max()		{ return type( TypeInfo< type::half_int_t >::Max(), TypeInfo< type::half_uint_t >::Max() ); }
		static			 type			Min()		{ return type( TypeInfo< type::half_int_t >::Min(), TypeInfo< type::half_uint_t >::Max() ); }
		
		static			 type			Epsilon()	{ return type( 0, 1 ); }
		static constexpr uint			SignBit()	{ return (sizeof(type)<<3)-1; }
		
		static const char *				Name()		{ return "fixed64"; }

		_CHECK_SIMILAR_TYPES();
	};


	_TYPE_INFO_WITH_INNER_TYPE( float32_t,	float32_t::Float_t, "float32" );
	_TYPE_INFO_WITH_INNER_TYPE( float64_t,	float64_t::Float_t, "float64" );

//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_TYPE_INFO_H